/*
 * Copyright 2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import * as _ from "lodash"
import { camelCase, snakeCase } from "../case"
import { PageList } from "../data"
import httpClient from "../httpclient"

export enum BlobType {
  File = "file",
  Directory = "directory",
}

export class Blob {
  public bucketId: string
  public id: string
  public path: string
  public name: string
  public type: BlobType
  public url: string
}

class BlobQuery {
  private bucketId_: string
  private params = {}

  public page(page: number) {
    this.params["page"] = page
    return this
  }

  public limit(limit: number) {
    this.params["limit"] = limit
    return this
  }

  public bucketId(bucketId: string) {
    this.bucketId_ = bucketId
    return this
  }

  public path(path: string) {
    this.params["path"] = path
    return this
  }

  public directory() {
    this.params["types"] = BlobType.Directory
    return this
  }

  public file() {
    this.params["types"] = BlobType.File
    return this
  }

  public list(): Promise<PageList<Blob>> {
    return httpClient.get(`/v1/buckets/${this.bucketId_}/blobs`, { params: this.params })
      .then(({ data }) => {
        return _.assign(PageList.empty(), data, {
          elements: _.map(data.elements, element => _.assign(new Blob(), element)),
        })
      })
  }
}

export interface BlobResource {
  bucketId: string
  path: string
  name?: string
  file?: any
}

export class StorageServiceV1 {

  public static storeBlob(resource: BlobResource): Promise<Blob> {
    const formData = new FormData()
    formData.append("file", resource.file)
    const path = _.startsWith(resource.path, "/") ? resource.path : "/" + resource.path
    formData.append("path", path)
    if (!_.isUndefined(resource.name)) {
      formData.append("name", resource.name)
    }
    return httpClient.post(`/v1/buckets/${resource.bucketId}/blobs`, formData, {
      headers: {
        "Content-Type": "multipart/form-data",
      },
    }).then(({ data }) => _.assign(new Blob(), data))
  }

  public static updateBlob(blob: Blob): Promise<Blob> {
    return httpClient.patch(`/v1/buckets/${blob.bucketId}/blobs/${blob.id}`, snakeCase(blob))
      .then(({ data }) => data)
      .then(camelCase)
  }

  public static deleteBlob(bucketId: string, blobId: string): Promise<void> {
    return httpClient.delete(`/v1/buckets/${bucketId}/blobs/${blobId}`)
  }

  public static deleteBlobs(bucketId: string, blobIds: string[]): Promise<void> {
    return httpClient.delete(`/v1/buckets/${bucketId}/blobs/batch`, {
      data: _.map(blobIds, blobId => ({ id: blobId })),
    })
  }

  public static createBlobQuery(): BlobQuery {
    return new BlobQuery()
  }
}
